package com.ibuonline.search.solr.extend;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.apache.lucene.document.Document;
import org.apache.lucene.search.Query;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.DeleteUpdateCommand;
import org.apache.solr.update.processor.UpdateRequestProcessor;
import org.apache.solr.update.processor.UpdateRequestProcessorFactory;

import com.ibuonline.search.solr.SpringContextHolder;

/**
 * Pass the command to the UpdateHandler without any modifications
 * 
 */
public class ExternalDataUpdateProcessorFactory extends
		UpdateRequestProcessorFactory {
	private static final String DOC_HANDLER = "doc-handler";
	private DocumentHandlerManager documentHandlerManager;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.solr.update.processor.UpdateRequestProcessorFactory#init(org
	 * .apache.solr.common.util.NamedList)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public void init(NamedList args) {
		super.init(args);

		// 获取外部数据处理者配置项
		String documentHandlerManagerName = (String) args.get(DOC_HANDLER);
		if (documentHandlerManagerName == null) {
			throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
					"the element '" + DOC_HANDLER + "' can't be null or empty.");
		}
		documentHandlerManagerName = documentHandlerManagerName.replaceAll(
				"\t|\r|\n", "");// 去除字符串中的回车/换行符/制表符
		documentHandlerManager = (DocumentHandlerManager) SpringContextHolder
				.getInstance().getContext().getBean(documentHandlerManagerName);
		if (documentHandlerManager == null) {
			throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
					"Not found bean :'" + documentHandlerManagerName
							+ "' in Spring Application Context.");
		}
	}

	@Override
	public UpdateRequestProcessor getInstance(SolrQueryRequest req,
			SolrQueryResponse rsp, UpdateRequestProcessor next) {
		return new ExternalDataUpdateProcessor(req, next,
				documentHandlerManager);
	}
}

class ExternalDataUpdateProcessor extends UpdateRequestProcessor {
	private final SolrQueryRequest req;
	private DocumentHandlerManager documentHandlerManager;
	private String idFieldName;

	public ExternalDataUpdateProcessor(SolrQueryRequest req,
			UpdateRequestProcessor next, DocumentHandlerManager docHander) {
		super(next);
		this.req = req;
		idFieldName = req.getSchema().getUniqueKeyField().getName();
		this.documentHandlerManager = docHander;
	}

	@Override
	public void processAdd(AddUpdateCommand cmd) throws IOException {
		boolean onlyExternal = false;
		if (documentHandlerManager != null) {
			SolrIndexContext context = new SolrIndexContext();
			context.setDocument(cmd.getSolrInputDocument());
			context.setRequest(this.req);
			context.setNextUpdateRequestProcessor(this.next);
			documentHandlerManager.add(context);
			onlyExternal = context.isOnlyExternal();
		}
		if (!onlyExternal) {
			super.processAdd(cmd);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.solr.update.processor.UpdateRequestProcessor#processDelete
	 * (org.apache.solr.update.DeleteUpdateCommand)
	 */
	@Override
	public void processDelete(DeleteUpdateCommand cmd) throws IOException {
		if (cmd.id != null) {
			documentHandlerManager.delete(cmd.id);
		} else {
			Set<String> fields = new HashSet<String>(1);
			fields.add(this.idFieldName);
			Query q = QueryParsing.parseQuery(cmd.query, req.getSchema());
			SolrIndexSearcher searcher = req.getSearcher();
			DocSet docSet = req.getSearcher().getDocSet(q);
			DocIterator iter = docSet.iterator();
			while (iter.hasNext()) {
				int docid = iter.nextDoc();
				Document doc = searcher.doc(docid, fields);
				String id = req.getSchema().getUniqueKeyField(doc)
						.stringValue();
				documentHandlerManager.delete(id);
			}
		}
		super.processDelete(cmd);
	}
}
